require 'test-unit-ext'

class TestXMLReport < Test::Unit::TestCase
  class TestCase < Test::Unit::TestCase
    def default_test
    end

    def _test_success
      assert(true)
    end

    TEST_FAILURE_LINE = __LINE__ + 3
    bug 1234
    def _test_failure
      assert(false)
    end

    TEST_ERROR_LINE = __LINE__ + 2
    def _test_error
      non_existence_method()
    end

    def inspect
      "TEST-CASE"
    end
  end

  include ERB::Util

  def test_empty_test
    assert_xml("<report/>", suite)
  end

  def test_success_result
    elapsed = "0.001"
    assert_xml(<<-XML, suite([TestCase.new("_test_success")]), elapsed)
<report>
  <result>
    <test_case>
      <name>TestXMLReport::TestCase</name>
      <description/>
    </test_case>
    <test>
      <name>_test_success</name>
      <description/>
    </test>
    <status>success</status>
    <detail></detail>
    <elapsed>#{elapsed}</elapsed>
  </result>
</report>
XML
  end

  def test_failure_result
    elapsed = "0.001"
    backtrace_line = __LINE__ + 1
    assert_xml(<<-XML, suite([TestCase.new("_test_failure")]), elapsed)
<report>
  <result>
    <test_case>
      <name>TestXMLReport::TestCase</name>
      <description/>
    </test_case>
    <test>
      <name>_test_failure</name>
      <description/>
      <option>
        <name>bug</name>
        <value>1234</value>
      </option>
    </test>
    <status>failure</status>
    <detail>&lt;false&gt; is not true.</detail>
    <elapsed>#{elapsed}</elapsed>
    <backtrace>
      <entry>
        <file>#{__FILE__}</file>
        <line>#{TestCase::TEST_FAILURE_LINE}</line>
        <info>in `_test_failure'</info>
      </entry>
      <entry>
        <file>#{__FILE__}</file>
        <line>#{TEST_RUN_LINE}</line>
        <info>in `assert_xml'</info>
      </entry>
      <entry>
        <file>#{__FILE__}</file>
        <line>#{backtrace_line}</line>
        <info>in `test_failure_result'</info>
      </entry>
    </backtrace>
  </result>
</report>
XML
  end

  def test_error_result
    test = TestCase.new("_test_error")
    detail = "NoMethodError: undefined method `non_existence_method' " +
      "for TEST-CASE:#{test.class.name}"
    elapsed = "0.001"
    backtrace_line = __LINE__ + 1
    assert_xml(<<-XML, suite([test]), elapsed)
<report>
  <result>
    <test_case>
      <name>TestXMLReport::TestCase</name>
      <description/>
    </test_case>
    <test>
      <name>_test_error</name>
      <description/>
    </test>
    <status>error</status>
    <detail>#{h(detail)}</detail>
    <elapsed>#{elapsed}</elapsed>
    <backtrace>
      <entry>
        <file>#{__FILE__}</file>
        <line>#{TestCase::TEST_ERROR_LINE}</line>
        <info>in `_test_error'</info>
      </entry>
      <entry>
        <file>#{__FILE__}</file>
        <line>#{TEST_RUN_LINE}</line>
        <info>in `assert_xml'</info>
      </entry>
      <entry>
        <file>#{__FILE__}</file>
        <line>#{backtrace_line}</line>
        <info>in `test_error_result'</info>
      </entry>
    </backtrace>
  </result>
</report>
XML
  end

  private
  def suite(tests=[], name="Unnamed TestSuite")
    test_suite = Test::Unit::TestSuite.new(name)
    tests.each do |test|
      test_suite << test
    end
    test_suite
  end

  TEST_RUN_LINE = __LINE__ + 2
  def assert_xml(expected, suite, normalized_elapsed=nil)
    result = Test::Unit::UI::Console::TestRunner.run(suite,
                                                     Test::Unit::UI::SILENT)
    xml = result.to_xml
    if xml and normalized_elapsed
      xml = xml.gsub(/<elapsed>[\d.]+<\/elapsed>/) do
        "<elapsed>#{normalized_elapsed}</elapsed>"
      end
    end
    assert_equal(expected, xml)
  end
end
